export default function createStatementData(invoice, plays) {
  const res = {};
  res.customer = invoice.customer;
  res.performance = invoice.performance.map(enrichPerformance);
  res.totalAmount = totalAmount(res);
  res.totalVolumeCredits = totalVolumeCredits(res);
  return res;

  function enrichPerformance(aPerformance) {
    const calculator = new createPerformanceCaculator(aPerformance, playFor(aPerformance));
    const res = Object.assign({}, aPerformance);
    res.play = calculator.play;
    res.amount = calculator.amount;
    res.volumeCredits = calculator.volumeCredits;
    return res;
  }

  function playFor(aPerformance) {
    return plays[aPerformance.playID]
  }

  function totalVolumeCredits(data) {
    return data.performance.reduce((total, pref) => total + pref.volumeCredits, 0);
  }
  function totalAmount(data) {
    return data.performance.reduce((total, pref) => total + pref.amount, 0);
  }
}

class PerformanceCaculator {
  constructor(aPerformance, aPlay) {
    this.performance = aPerformance;
    this.play = aPlay
  }
  get amount() {
    throw new Error('由子类负责计算')
  }
  get volumeCredits() {
    return Math.max(this.performance.audience - 30, 0)
  }
}

// 使用工厂函数取代构造函数
// 在里面创建演出计算器的子类，由创建函数决定返回哪个子类的实例
function createPerformanceCaculator(aPerformance, aPlay) {
  switch (aPlay.type) {
    case "悲剧": return new TragedyCalculator(aPerformance, aPlay);
    case "喜剧": return new ComedyCalculator(aPerformance, aPlay);
    default: throw new Error(`unknow type: ${aPlay.type}`);
  }
}

// 包含计算悲剧的逻辑
class TragedyCalculator extends PerformanceCaculator {
  get amount() {
    let res = 40000;
    if (this.performance.audience > 30) {
      res += 1000 * (this.performance.audience - 30);
    }
    return res
  }
}

// 计算喜剧的逻辑
class ComedyCalculator extends PerformanceCaculator {
  get amount() {
    let res = 30000;
    if (this.performance.audience > 20) {
      res += 10000 + 500 * (this.performance.audience - 20);
    }
    res += 300 * this.performance.audience
    return res
  }
  get volumeCredits() {
    return super.volumeCredits + Math.floor(this.performance.audience / 5)
  }
}